"""
Data models for restaurant information
"""
from datetime import datetime
from typing import Optional
from pydantic import BaseModel, Field, validator
from sqlalchemy import Column, Integer, String, DateTime, Float, Text, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

Base = declarative_base()


class RestaurantData(BaseModel):
    """Pydantic model for restaurant data validation"""
    
    name: str = Field(..., description="Restaurant/Brand name")
    category: Optional[str] = Field(None, description="Cuisine type/Category")
    city: str = Field(..., description="City location")
    location: Optional[str] = Field(None, description="Detailed location/Address")
    price_range: Optional[str] = Field(None, description="Average order value/Price range")
    phone: Optional[str] = Field(None, description="Contact phone number")
    platform: str = Field(..., description="Source platform (eleme/meituan/dianping)")
    url: Optional[str] = Field(None, description="Restaurant page URL")
    scraped_at: datetime = Field(default_factory=datetime.now)
    
    @validator('phone')
    def validate_phone(cls, v):
        """Validate phone number format"""
        if v is None:
            return v
        # Remove common separators and spaces
        cleaned = ''.join(filter(str.isdigit, v))
        # Chinese phone numbers are typically 11 digits for mobile, 10-12 for landline
        if len(cleaned) < 7 or len(cleaned) > 15:
            return None
        return v
    
    @validator('platform')
    def validate_platform(cls, v):
        """Ensure platform is one of the supported ones"""
        if v not in ['eleme', 'meituan', 'dianping']:
            raise ValueError('Platform must be one of: eleme, meituan, dianping')
        return v
    
    class Config:
        json_encoders = {
            datetime: lambda v: v.isoformat()
        }


class Restaurant(Base):
    """SQLAlchemy model for restaurant data storage"""
    
    __tablename__ = 'restaurants'
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(255), nullable=False, index=True)
    category = Column(String(100), index=True)
    city = Column(String(50), nullable=False, index=True)
    location = Column(Text)
    price_range = Column(String(100))
    phone = Column(String(50))
    platform = Column(String(20), nullable=False, index=True)
    url = Column(Text)
    scraped_at = Column(DateTime, default=datetime.now, index=True)
    
    def __repr__(self):
        return f"<Restaurant(name='{self.name}', city='{self.city}', platform='{self.platform}')>"
    
    def to_dict(self):
        """Convert to dictionary for JSON serialization"""
        return {
            'id': self.id,
            'name': self.name,
            'category': self.category,
            'city': self.city,
            'location': self.location,
            'price_range': self.price_range,
            'phone': self.phone,
            'platform': self.platform,
            'url': self.url,
            'scraped_at': self.scraped_at.isoformat() if self.scraped_at else None
        }


class ScrapingSession(Base):
    """Track scraping sessions for monitoring and debugging"""
    
    __tablename__ = 'scraping_sessions'
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    platform = Column(String(20), nullable=False)
    city = Column(String(50), nullable=False)
    started_at = Column(DateTime, default=datetime.now)
    completed_at = Column(DateTime)
    restaurants_scraped = Column(Integer, default=0)
    errors_count = Column(Integer, default=0)
    status = Column(String(20), default='running')  # running, completed, failed
    error_message = Column(Text)
    
    def __repr__(self):
        return f"<ScrapingSession(platform='{self.platform}', city='{self.city}', status='{self.status}')>"


class DatabaseManager:
    """Database connection and session management"""
    
    def __init__(self, database_url: str):
        self.engine = create_engine(database_url)
        self.SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=self.engine)
        
    def create_tables(self):
        """Create all tables"""
        Base.metadata.create_all(bind=self.engine)
        
    def get_session(self):
        """Get database session"""
        return self.SessionLocal()
        
    def save_restaurant(self, restaurant_data: RestaurantData):
        """Save restaurant data to database"""
        session = self.get_session()
        try:
            restaurant = Restaurant(
                name=restaurant_data.name,
                category=restaurant_data.category,
                city=restaurant_data.city,
                location=restaurant_data.location,
                price_range=restaurant_data.price_range,
                phone=restaurant_data.phone,
                platform=restaurant_data.platform,
                url=restaurant_data.url,
                scraped_at=restaurant_data.scraped_at
            )
            session.add(restaurant)
            session.commit()
            return restaurant.id
        except Exception as e:
            session.rollback()
            raise e
        finally:
            session.close()
            
    def get_restaurants(self, platform: str = None, city: str = None, limit: int = None):
        """Retrieve restaurants with optional filtering"""
        session = self.get_session()
        try:
            query = session.query(Restaurant)
            if platform:
                query = query.filter(Restaurant.platform == platform)
            if city:
                query = query.filter(Restaurant.city == city)
            if limit:
                query = query.limit(limit)
            return query.all()
        finally:
            session.close()
            
    def create_scraping_session(self, platform: str, city: str):
        """Create new scraping session record"""
        session = self.get_session()
        try:
            scraping_session = ScrapingSession(
                platform=platform,
                city=city
            )
            session.add(scraping_session)
            session.commit()
            return scraping_session.id
        except Exception as e:
            session.rollback()
            raise e
        finally:
            session.close()
            
    def update_scraping_session(self, session_id: int, **kwargs):
        """Update scraping session with results"""
        session = self.get_session()
        try:
            scraping_session = session.query(ScrapingSession).filter(
                ScrapingSession.id == session_id
            ).first()
            if scraping_session:
                for key, value in kwargs.items():
                    setattr(scraping_session, key, value)
                session.commit()
        except Exception as e:
            session.rollback()
            raise e
        finally:
            session.close()
